/**
 * Project: prepose-client-biz-proxy
 * 
 * File Created at 2014-3-13
 * 
 * Copyright 2012 Greenline.com Corporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * Greenline Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Greenline.com.
 */
package org.xukai.common.Proxy;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * Type: ProxyConfigsFactory <br>
 * Date: 2014-3-13 <br>
 * Desc:
 * 
 * @author jianyun.zheng
 * @version V1.0
 */
public enum ProxyConfigsFactory {

    proxyInstance;
    static Log logger = LogFactory.getLog(ProxyConfigsFactory.class);

    private final ConcurrentMap<String, Object> classMaps = new ConcurrentHashMap<String, Object>();
    private final ConcurrentMap<String, Method> methodMaps = new ConcurrentHashMap<String, Method>();
    private final ConcurrentMap<String, ProxyData> proxyMaps = new ConcurrentHashMap<String, ProxyData>();

    public boolean load(List<ProxyData> listProxy) {
        return initMap(proxyMaps, listProxy);
    }


    public static <T> boolean initMap(Map<String, T> map, List<ProxyData> list) {
        boolean flag = false;
        try {
            Assert.notEmpty(list, "list为空");
            map.clear();
            for (ProxyData da : list) {
                // 只有InterFaceData的管理用name做key其他的都用id做key（ftp,db,sql）
                if (da instanceof ProxyData) {
                } else {
                }
            }
            flag = true;
        } catch (Exception e) {
            logger.error(e);
            flag = false;
        }
        return flag;
    }

    public ProxyData getProxyData(String proxyId) {
        if (proxyMaps.isEmpty()) {
            return null;
        }
        return proxyMaps.get(proxyId);
    }

    private String getkey(String str1, String str2) {
        return str1 + "|" + str2;
    }

    private URL[] getURL(ProxyData p) throws Exception {
        String error = null;

        File f = new File(p.getJarPath());
        if (!f.exists()) {
            error = p.getJarPath() + " JarPath is not a correct path";
            logger.error(error);
            throw new IllegalArgumentException(error);
        }

        if (f.isFile()) {
            URL url = new URL(p.getJarPath());
            return new URL[] { url };
        } else if (f.isDirectory()) {
            File[] files = f.listFiles();
            List<URL> list = new ArrayList<URL>();

            for (File file : files) {
                if (file.exists() && file.isFile()) {
                    list.add(file.toURI().toURL());
                }
            }
            return list.toArray(new URL[0]);
        }
        return null;

    }

    private Object newInstance(ProxyData p) throws Exception {
        String error = "";
        String path = p.getJarPath();
        if (p == null || path == null || path.isEmpty()) {
            error = "JarPath is null";
            logger.error(error);
            throw new IllegalArgumentException(error);
        }

        ClassLoader cl = new URLClassLoader(getURL(p));
        // fix bug
        // Thread.currentThread().setContextClassLoader(cl);
        Class<?> c = cl.loadClass(p.getClassName());// 从加载器中加载Class


//得到系统类加载器
//        URLClassLoader urlClassLoader= (URLClassLoader) ClassLoader.getSystemClassLoader();
//因为URLClassLoader中的addURL方法的权限为protected所以只能采用反射的方法调用addURL方法
//        Method add = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class });
//        add.setAccessible(true);
//        add.invoke(urlClassLoader, new Object[] {getURL(p) });
//        Class c=Class.forName(p.getClassName());
//        Class c=urlClassLoader.loadClass("类名");


        return c.newInstance();
    }

    public static void main(String[] args) throws Exception {
        ProxyData p = new ProxyData();
        p.setJarPath("E:\\IDEA_workSpace\\xukai_basic\\basic-web\\target\\basic.web-1.0-SNAPSHOT\\WEB-INF\\lib");
        p.setClassName("org.xukai.common.util.UIDUtils");
        p.setMethodName("getReqNo");

        ProxyRequest request = new ProxyRequest();
        Map<String, Object> map = new HashMap<String, Object>();
//        map.put("mobile", "12312231");
        request.setParams(map);

        System.out.println(ProxyConfigsFactory.proxyInstance.invokeMethod(p, request));
    }

    private Method getMethod(ProxyData p, Object myObject) throws Exception {
        Method[] methods = myObject.getClass().getDeclaredMethods();
        for (Method method : methods){
            System.out.println(method.getName());
        }
        return myObject.getClass().getDeclaredMethod(p.getMethodName());
    }

    public Object invokeMethod(ProxyData p, ProxyRequest request) throws Exception {
        String key1 = this.getkey(p.getJarPath(), p.getClassName());
        Object myObject = classMaps.get(key1);
        if (null == myObject) {
            myObject = proxyInstance.newInstance(p);
            classMaps.put(key1, myObject);
        }
        Assert.notNull(myObject, "jar.class is not exist, jar.class:" + key1);
        String key2 = this.getkey(key1, p.getMethodName());
        Method m = methodMaps.get(key2);
        if (null == m) {
            m = proxyInstance.getMethod(p, myObject);
            methodMaps.put(key2, m);
        }
        Assert.notNull(m, "jar.class.method is not exist, jar.class.method:" + key2);
        m.setAccessible(true);
        // fix bug
        Thread.currentThread().setContextClassLoader(myObject.getClass().getClassLoader());
        return m.invoke(myObject);
    }
}
